home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / vts139b.zip / SONGUNIT.PAS < prev    next >
Pascal/Delphi Source File  |  1993-11-25  |  16KB  |  582 lines

  1. {****************************************************************************}
  2. {                                                                            }
  3. { MODULE:        SongUnit                                                    }
  4. {                                                                            }
  5. { DESCRIPTION:   Gives the necessary support for handling the different      }
  6. {                data types and different file formats of a song. Also, it   }
  7. {                implements the base routines for loading the song from many }
  8. {                different file formats and (future) saving them to disk.    }
  9. {                                                                            }
  10. { AUTHOR:        Juan Carlos Arévalo Baeza                                   }
  11. {                                                                            }
  12. { MODIFICATIONS: Nobody (yet).                                               }
  13. {                                                                            }
  14. { HISTORY:       xx-May-1992 First implementations (lost in the memory of    }
  15. {                            time O:-).                                      }
  16. {                xx-Jun-1992 Lots of improvements (ditto O;-).               }
  17. {                11-Jul-1992 Started first documented version.               }
  18. {                21-Oct-1992 Rechecking. First remodeling.                   }
  19. {                25-Jan-1993 Created the .OKT and .WOW loader.               }
  20. {                06-Feb-1993 Remodelling. Made the memory-optimized, object- }
  21. {                            oriented interface. Name change from ModUnit.   }
  22. {                                                                            }
  23. { (C) 1992, 1993 VangeliSTeam                                                }
  24. {____________________________________________________________________________}
  25.  
  26. UNIT SongUnit;
  27.  
  28. INTERFACE
  29.  
  30. USES Dos, Objects,
  31.      HexConversions,
  32.      SongElements;
  33.  
  34.  
  35.  
  36.  
  37. {----------------------------------------------------------------------------}
  38. { Song object definition.                                                    }
  39. {____________________________________________________________________________}
  40.  
  41. TYPE
  42.   TSongFileFormat =
  43.     (
  44.       mffUnknown      ,    { Unknown format O:-)                      }
  45.       mffMod31M_K_    ,    { Protracker "M.K.".                       }
  46.       mffMod31FLT4    ,    { Protracker "FLT4".                       }
  47.       mffMod15        ,    { SoundTracker 15-instrument module.       }
  48.       mffJMPlayer     ,    { JMPlayer module.                         }
  49.       mffOktalizer    ,    { 8 voices Oktalizer MOD.           (.OKT) }
  50.       mffComposer669  ,    { 8 voices Composer-669.            (.669) }
  51.       mffWow8         ,    { 8 voices Grave.                   (.WOW) }
  52.       mffFastTracker  ,    { 6 or 8 voices Triton FastTracker. (.MOD) }
  53.       mffS3m          ,    { ScreamTracker 3.0                 (.S3M) }
  54.       mffS2m          ,    { ScreamTracker 3.0 (beta)          (.S2M) }
  55.       mffStm               { ScreamTracker 2.x                 (.STM) }
  56.     );
  57.  
  58.   TSongStatus =
  59.     (
  60.       { Non fatal states }
  61.  
  62.       msNotLoaded              ,    { Not yet loaded                                         }
  63.       msOK                     ,    { Everything was Ok.                                     }
  64.       msFileTooShort           ,    { End of file premature (lot's of modules have this).    }
  65.  
  66.       { Fatal states }
  67.  
  68.       msFileOpenError          ,    { Could not open the .MOD file.                          }
  69.       msOutOfMemory            ,    { There is not enough memory left. :-( Shouldn't happen. }
  70.       msFileDamaged            ,    { Syntax checking error on module file.                  }
  71.       msFileFormatNotSupported      { JMPlayer or ScreamTracker, for example.                }
  72.     );
  73.  
  74.  
  75. TYPE
  76.   TPanPositions = ARRAY[1..32] OF BYTE;
  77.  
  78.   PSong = ^TSong;
  79.   TSong =
  80.     OBJECT(TObject)
  81.  
  82.       { Desired data }
  83.  
  84.       SongStart             : WORD;
  85.       SongLen               : WORD;
  86.  
  87.       { General song data }
  88.  
  89.       Name                  : PString;
  90.       InsidePath            : PString;
  91.       Comment               : PSongComment;
  92.       FileDir               : PString;
  93.       FileName              : NameStr;
  94.       FileExt               : ExtStr;
  95.       FirstTick             : BOOLEAN;
  96.       InitialTempo          : BYTE;
  97.       InitialBPM            : BYTE;
  98.       Volume                : BYTE;
  99.       NumChannels           : BYTE;
  100.       PanPositions          : TPanPositions;
  101.  
  102.       { Instrument data }
  103.  
  104.       Instruments           : TCollection;
  105.  
  106.       { Pattern sequence data }
  107.  
  108.       SequenceLength        : WORD;
  109.       SequenceRepStart      : WORD;
  110.       PatternSequence       : PPatternSequence;
  111.       PatternTempos         : PPatternSequence;
  112.  
  113.       Patterns              : TCollection;
  114.  
  115.       { Track data }
  116.  
  117.       Tracks                : TCollection;
  118.  
  119.       { State data }
  120.  
  121.       Status                : TSongStatus;
  122.       ErrorCode             : WORD;
  123.       ThereIsMore           : BOOLEAN;
  124.       FileFormat            : TSongFileFormat;
  125.  
  126.  
  127.  
  128.       { Methods }
  129.  
  130.       CONSTRUCTOR Init;
  131.       DESTRUCTOR  Done; VIRTUAL;
  132.  
  133.       PROCEDURE Load(VAR St: TStream);
  134.       PROCEDURE Save(VAR St: TStream);
  135.  
  136.       PROCEDURE LoadFName(FName: PathStr);
  137.       PROCEDURE SaveFName(FName: PathStr);
  138.  
  139.       PROCEDURE Free;
  140.       PROCEDURE InitValues;
  141.       PROCEDURE Empty;
  142.  
  143.       FUNCTION  GetErrorString                            : STRING;
  144.  
  145.       FUNCTION  GetName                                   : STRING;
  146.       FUNCTION  GetInsidePath                             : STRING;
  147.       FUNCTION  GetInstrument      (i: WORD)              : PInstrument;
  148.       FUNCTION  GetTrack           (i: WORD)              : PTrack;
  149.       FUNCTION  GetPattern         (i: WORD)              : PPattern;
  150.       FUNCTION  GetPatternSeq      (i: WORD)              : PPattern;
  151.       FUNCTION  GetPatternSequence (Seq: WORD)            : WORD;
  152.       FUNCTION  GetPatternTempo    (Seq: WORD)            : WORD;
  153.       PROCEDURE GetNote            (Seq, Row, Chan: WORD; VAR Note: TFullNote);
  154.  
  155.       PROCEDURE SetName            (S: STRING);
  156.       PROCEDURE SetInsidePath      (S: STRING);
  157.     END;
  158.  
  159.  
  160.  
  161.  
  162. {----------------------------------------------------------------------------}
  163. { Header definition for the loaders.                                         }
  164. {____________________________________________________________________________}
  165.  
  166. TYPE
  167.   PSongHeader = ^TSongHeader;
  168.   TSongHeader = ARRAY[0..2047] OF BYTE;
  169.  
  170.  
  171. CONST
  172.   ModOffset : LONGINT = 0;
  173.  
  174.  
  175.  
  176. IMPLEMENTATION
  177.  
  178. USES SongUtils,
  179.      UnkLoader, ModLoader, OktLoader, S3mLoader, StmLoader, Loader669, ExeLoader,
  180.      Heaps,
  181.      StrConst, AsciiZ, Filters;
  182.  
  183.  
  184.  
  185.  
  186. {----------------------------------------------------------------------------}
  187. { Loaders definition.                                                        }
  188. {____________________________________________________________________________}
  189.  
  190. TYPE
  191.   TSongLoader = PROCEDURE (VAR Song: TSong; VAR St: TStream; VAR Header: TSongHeader);
  192.  
  193. CONST
  194.   NumLoaders = 8;
  195.  
  196.   SongLoaders : ARRAY[1..NumLoaders] OF TSongLoader =
  197.     (
  198.       LoadJMFileFormat,
  199.       Load669FileFormat,
  200.       LoadOktFileFormat,
  201.       LoadS2mFileFormat,
  202.       LoadS3mFileFormat,
  203.       LoadStmFileFormat,
  204.       LoadExeFileFormat,
  205.       LoadModFileFormat
  206.     );
  207.  
  208.  
  209.  
  210.  
  211. {----------------------------------------------------------------------------}
  212. { TSong object.                                                              }
  213. {____________________________________________________________________________}
  214.  
  215. CONSTRUCTOR TSong.Init;
  216.   BEGIN
  217.     TObject.Init;
  218.     InitValues;
  219.   END;
  220.  
  221.  
  222. DESTRUCTOR  TSong.Done; 
  223.   BEGIN
  224.     Free;
  225.     TObject.Done;
  226.   END;
  227.  
  228.  
  229. PROCEDURE TSong.Load(VAR St: TStream);
  230.   VAR
  231.     Header : TSongHeader;
  232.     i      : WORD;
  233.     Pos    : LONGINT;
  234.   BEGIN
  235.     Pos := St.GetPos;
  236.  
  237.     ThereIsMore := FALSE;
  238.  
  239.     St.Read(Header, SIZEOF(TSongHeader));
  240.  
  241.     IF St.Status <> stOk THEN
  242.       BEGIN
  243.         Status    := msFileDamaged;
  244.         ErrorCode := St.ErrorInfo;
  245.         St.Done;
  246.         EXIT;
  247.       END;
  248.  
  249.     i := 1;
  250.     WHILE (i     <= NumLoaders)  AND
  251.           (Status = msNotLoaded) DO
  252.       BEGIN
  253.         St.Seek(Pos);
  254.         SongLoaders[i](PSong(@Self)^, St, Header);
  255.         INC(i);
  256.       END;
  257.   END;
  258.  
  259.  
  260. PROCEDURE TSong.LoadFName(FName: PathStr);
  261.   VAR
  262.     St         : TDosStream;
  263.     Dir        : DirStr;
  264.     IPath      : STRING[12];
  265.     OSongStart : WORD;
  266.     OSongLen   : WORD;
  267.   BEGIN
  268.     OSongStart := SongStart;
  269.     OSongLen   := SongLen;
  270.     IPath := GetInsidePath;
  271.     Empty;
  272.     SetInsidePath(IPath);
  273.     SongStart := OSongStart;
  274.     SongLen   := OSongLen;
  275.  
  276.     FName := FExpand(FName);
  277.     FSplit(FName, Dir, FileName, FileExt);
  278.     FileDir := FullHeap.HNewStr(Dir);
  279.     IF FileExt = '' THEN FileExt := '.MOD';
  280.     FName := Dir+FileName+FileExt;
  281.  
  282.     St.Init(FName, stOpenRead);
  283.     St.Seek(ModOffset);
  284.  
  285.     IF St.Status <> stOk THEN
  286.       BEGIN
  287.         Status    := msFileOpenError;
  288.         ErrorCode := St.ErrorInfo;
  289.         St.Done;
  290.         EXIT;
  291.       END;
  292.  
  293.     Status    := msNotLoaded;
  294.     ErrorCode := 0;
  295.  
  296.     Load(St);
  297.  
  298.     IF Status <> msOk THEN
  299.       ErrorCode := St.ErrorInfo;
  300.  
  301.     St.Done;
  302.   END;
  303.  
  304.  
  305. PROCEDURE TSong.Save(VAR St: TStream);
  306.   BEGIN
  307.   END;
  308.  
  309.  
  310. PROCEDURE TSong.SaveFName(FName: PathStr);
  311.   BEGIN
  312.   END;
  313.  
  314.  
  315. FUNCTION TSong.GetErrorString : STRING;
  316.   BEGIN
  317.     CASE Status OF
  318.       msFileOpenError:          GetErrorString := GetString(StrFileOpenError);
  319.       msOutOfMemory:            GetErrorString := GetString(StrOutOfMemory);
  320.       msFileDamaged:            GetErrorString := GetString(StrFileDamaged);
  321.       msFileTooShort:           GetErrorString := GetString(StrFileTooShort);
  322.       msFileFormatNotSupported: GetErrorString := GetString(StrFileFormatNotSupported) +
  323.                                                   GetString(StrFileFormats + BYTE(FileFormat));
  324.       ELSE                      GetErrorString := '';
  325.     END;
  326.   END;
  327.  
  328.  
  329. FUNCTION TSong.GetName : STRING;
  330.   BEGIN
  331.     IF Name <> NIL THEN
  332.       GetName := Name^
  333.     ELSE
  334.       GetName := '';
  335.   END;
  336.  
  337.  
  338. PROCEDURE TSong.SetName(S: STRING);
  339.   BEGIN
  340.     IF Name <> NIL THEN
  341.       FullHeap.HDisposeStr(Name);
  342.  
  343.     IF S <> '' THEN
  344.       Name := FullHeap.HNewStr(S);
  345.   END;
  346.  
  347.  
  348. FUNCTION TSong.GetInsidePath : STRING;
  349.   BEGIN
  350.     IF InsidePath <> NIL THEN
  351.       GetInsidePath := InsidePath^
  352.     ELSE
  353.       GetInsidePath := '';
  354.   END;
  355.  
  356.  
  357. PROCEDURE TSong.SetInsidePath(S: STRING);
  358.   BEGIN
  359.     IF InsidePath <> NIL THEN
  360.       FullHeap.HDisposeStr(InsidePath);
  361.  
  362.     IF S <> '' THEN
  363.       InsidePath := FullHeap.HNewStr(S);
  364.   END;
  365.  
  366.  
  367. FUNCTION TSong.GetInstrument(i: WORD) : PInstrument;
  368.   VAR
  369.     Instrument : PInstrument;
  370.     j          : WORD;
  371.   LABEL
  372.     Break;
  373.   BEGIN
  374.     IF i >= Instruments.Count THEN
  375.       BEGIN
  376.         FOR j := Instruments.Count TO i DO
  377.           BEGIN
  378.             Heap.HGetMem(POINTER(Instrument), SizeOf(TInstrument));
  379.             IF Instrument <> NIL THEN
  380.               BEGIN
  381.                 Instrument^.Init;
  382.                 Instruments.AtInsert(j, Instrument);
  383.               END
  384.             ELSE
  385.               GOTO Break;
  386.           END;
  387. Break:
  388.         GetInstrument := Instrument;
  389.       END
  390.     ELSE
  391.       GetInstrument := PInstrument(Instruments.At(i));
  392.   END;
  393.  
  394.  
  395. FUNCTION TSong.GetTrack(i: WORD) : PTrack;
  396.   VAR
  397.     Track : PTrack;
  398.     j     : WORD;
  399.   LABEL
  400.     Break;
  401.   BEGIN
  402.     IF i >= Tracks.Count THEN
  403.       BEGIN
  404.         FOR j := Tracks.Count TO i DO
  405.           BEGIN
  406.             Heap.HGetMem(POINTER(Track), SizeOf(TTrack));
  407.             IF Track <> NIL THEN
  408.               BEGIN
  409.                 Track^.Init;
  410.                 Tracks.AtInsert(j, Track);
  411.               END
  412.             ELSE
  413.               GOTO Break;
  414.           END;
  415. Break:
  416.         GetTrack := Track;
  417.       END
  418.     ELSE
  419.       GetTrack := PTrack(Tracks.At(i));
  420.   END;
  421.  
  422.  
  423. FUNCTION TSong.GetPattern(i: WORD) : PPattern;
  424.   VAR
  425.     Pattern : PPattern;
  426.     j       : WORD;
  427.   LABEL
  428.     Break;
  429.   BEGIN
  430.     IF i >= Patterns.Count THEN
  431.       BEGIN
  432.         FOR j := Patterns.Count TO i DO
  433.           BEGIN
  434.             Heap.HGetMem(POINTER(Pattern), SizeOf(TPattern));
  435.             IF Pattern <> NIL THEN
  436.               BEGIN
  437.                 Pattern^.Init(NumChannels);
  438.                 Patterns.AtInsert(j, Pattern);
  439.               END
  440.             ELSE
  441.               GOTO Break;
  442.           END;
  443. Break:
  444.         GetPattern := Pattern;
  445.       END
  446.     ELSE
  447.       GetPattern := PPattern(Patterns.At(i));
  448.   END;
  449.  
  450.  
  451. FUNCTION TSong.GetPatternSeq(i: WORD) : PPattern;
  452.   BEGIN
  453.     GetPatternSeq := GetPattern(GetPatternSequence(i));
  454.   END;
  455.  
  456.  
  457. FUNCTION TSong.GetPatternSequence(Seq: WORD) : WORD;
  458.   BEGIN
  459.     IF PatternSequence <> NIL THEN
  460.       GetPatternSequence := PatternSequence^[WORD(Seq)]
  461.     ELSE
  462.       GetPatternSequence := 0;
  463.   END;
  464.  
  465.  
  466. FUNCTION TSong.GetPatternTempo(Seq: WORD) : WORD;
  467.   BEGIN
  468.     IF PatternTempos <> NIL THEN
  469.       GetPatternTempo := PatternTempos^[WORD(Seq)]
  470.     ELSE
  471.       GetPatternTempo := 0;
  472.   END;
  473.  
  474.  
  475. PROCEDURE TSong.GetNote(Seq, Row, Chan: WORD; VAR Note: TFullNote);
  476.   VAR
  477.     Patt  : PPattern;
  478.     Track : PTrack;
  479.     n     : WORD;
  480.     NOffs : WORD;
  481.   BEGIN
  482.     IF PatternSequence <> NIL THEN
  483.       BEGIN
  484.         Patt := GetPatternSeq(Seq);
  485.         IF Patt <> NIL THEN
  486.           BEGIN
  487.             n     := Patt^.Patt^.Channels[Chan];
  488.             Track := GetTrack(n);
  489.             IF Track <> NIL THEN
  490.               BEGIN
  491.                 Track^.GetNote(Row, Note);
  492.                 EXIT;
  493.               END
  494.           END
  495.       END;
  496.  
  497.     FillChar(Note, SizeOf(Note), 0);
  498.   END;
  499.  
  500.  
  501. PROCEDURE TSong.Free;
  502.   VAR
  503.     i : WORD;
  504.   BEGIN
  505.     ASM CLI END;
  506.  
  507.     FullHeap.HDisposeStr(Name);
  508.     FullHeap.HFreeMem   (POINTER(Comment), SizeOf(Comment^));
  509.     FullHeap.HDisposeStr(FileDir);
  510.  
  511.     Instruments.Done;
  512.  
  513.     FullHeap.HFreeMem(POINTER(PatternSequence), SizeOf(PatternSequence^));
  514.     FullHeap.HFreeMem(POINTER(PatternTempos),   SizeOf(PatternTempos^));
  515.     Patterns.Done;
  516.  
  517.     Tracks.Done;
  518.  
  519.     ASM STI END;
  520.   END;
  521.  
  522.  
  523.  
  524. PROCEDURE TSong.InitValues;
  525.   CONST
  526.     DefPan : TPanPositions = ( $40, $B0, $B0, $40, $40, $B0, $B0, $40,
  527.                                $40, $B0, $B0, $40, $40, $B0, $B0, $40,
  528.                                $40, $B0, $B0, $40, $40, $B0, $B0, $40,
  529.                                $40, $B0, $B0, $40, $40, $B0, $B0, $40 );
  530.   BEGIN
  531.     SongStart    := 1;
  532.     SongLen      := MaxSequence;
  533.  
  534.     Name         := NIL;
  535.     InsidePath   := NIL;
  536.     Comment      := NIL;
  537.     FileDir      := NIL;
  538.     FileName     := '';
  539.     FileExt      := '';
  540.     FirstTick    := FALSE;
  541.     InitialTempo := 1;
  542.     InitialBPM   := 1;
  543.     Volume       := 0;
  544.     NumChannels  := 0;
  545.  
  546.     Instruments.Init(32, 32);
  547.  
  548.     SequenceLength   := 0;
  549.     SequenceRepStart := 0;
  550.  
  551.     FullHeap.HGetMem(POINTER(PatternSequence), SizeOf(PatternSequence^));
  552.     FullHeap.HGetMem(POINTER(PatternTempos),   SizeOf(PatternTempos^));
  553.     IF PatternSequence <> NIL THEN
  554.       FillChar(PatternSequence^, SizeOf(PatternSequence^), 0);
  555.     IF PatternTempos <> NIL THEN
  556.       FillChar(PatternTempos^, SizeOf(PatternTempos^), 0);
  557.     Patterns.Init(64, 64);
  558.  
  559.     Tracks.Init(256, 256);
  560.  
  561.     Status      := msNotLoaded;
  562.     ErrorCode   := 0;
  563.     ThereIsMore := FALSE;
  564.     FileFormat  := mffUnknown;
  565.  
  566.     PanPositions := DefPan;
  567.   END;
  568.  
  569.  
  570.  
  571.  
  572. PROCEDURE TSong.Empty;
  573.   BEGIN
  574.     Free;
  575.     InitValues;
  576.   END;
  577.  
  578.  
  579.  
  580.  
  581. END.
  582.